import logging
import time

from sqlalchemy import insert, select, update
import user_agents
from fastapi import Request, Depends

from forward.api.admin.config import AdminConfig
from forward.dependencies.database import db
from forward.exceptions.base import AppException
from forward.http_base import HttpResp
from forward.model.tables import SystemAuthAdminModel, SystemLogLoginModel
from forward.model.tables.system import SystemAuthAdminModel
from forward.utils.redis import RedisUtil
from forward.utils.tools import ToolsUtil
from forward.api.admin.service.system.auth_admin import SystemAuthAdminService
from forward.api.admin.schemas.system import (
    SystemLoginInSchema,
    SystemLoginOutSchema,
    SystemLogoutInSchema,
)


class SystemLoginService:
    """系统登录服务实现类"""

    def __init__(self, request: Request, auth_service: SystemAuthAdminService):
        self.request: Request = request
        self.auth_admin_service: SystemAuthAdminService = auth_service

    @classmethod
    async def instance(
        cls,
        request: Request,
        auth_admin_service: SystemAuthAdminService = Depends(
            SystemAuthAdminService.instance
        ),
    ):
        """实例化"""
        return cls(request, auth_admin_service)

    async def login(self, login_in: SystemLoginInSchema) -> SystemLoginOutSchema:
        """登录"""
        sys_admin = await self.auth_admin_service.find_by_username(login_in.username)
        # print("sys_admin", sys_admin.id if sys_admin else None, type(sys_admin))
        if not sys_admin or sys_admin.is_delete == 1:
            await self.record_login_log(
                0, login_in.username, HttpResp.LOGIN_ACCOUNT_ERROR.msg
            )
            raise AppException(HttpResp.LOGIN_ACCOUNT_ERROR)
        if sys_admin.is_disable:
            await self.record_login_log(
                sys_admin.id, sys_admin.username, HttpResp.LOGIN_DISABLE_ERROR.msg
            )
            raise AppException(HttpResp.LOGIN_DISABLE_ERROR)
        md5_pwd = ToolsUtil.make_md5(f"{login_in.password}{sys_admin.salt}")
        if sys_admin.password != md5_pwd:  # type: ignore
            await self.record_login_log(
                sys_admin.id, sys_admin.username, HttpResp.LOGIN_ACCOUNT_ERROR.msg
            )
            raise AppException(HttpResp.LOGIN_ACCOUNT_ERROR)
        try:
            # 非多处登录
            token = ToolsUtil.make_token()
            if not sys_admin.is_multipoint:
                sys_admin_set_key = f"{AdminConfig.backstage_token_set}{sys_admin.id}"
                ts = await RedisUtil.sget(sys_admin_set_key)
                if ts:
                    await RedisUtil.delete(
                        *(f"{AdminConfig.backstage_token_key}{t}" for t in ts)
                    )
                await RedisUtil.delete(sys_admin_set_key)
                await RedisUtil.sset(sys_admin_set_key, token)

            # 缓存登录信息
            await RedisUtil.set(
                f"{AdminConfig.backstage_token_key}{token}", sys_admin.id, 7200
            )
            await self.auth_admin_service.cache_admin_user_by_uid(sys_admin.id)
            # res = await RedisUtil.hmset(
            #     f"{AdminConfig.backstage_manage_key}{sys_admin.id}",
            #     {
            #         "username": sys_admin.username,
            #         "is_delete": sys_admin.is_delete,
            #         "is_disable": sys_admin.is_disable,
            #     },
            #     7200,
            # )
           
            # 更新登录信息
            row_update = (
                update(SystemAuthAdminModel)
                .where(SystemAuthAdminModel.id == sys_admin.id)
                .values(
                    last_login_ip=(
                        self.request.client.host if self.request.client else ""
                    ),
                    last_login_time=int(time.time()),
                )
            )
            await db.execute(row_update)
            # 记录登录日志
            await self.record_login_log(sys_admin.id, sys_admin.username)
            # 返回登录信息
            return SystemLoginOutSchema(token=token)
        except Exception as e:
            err_msg = str(e)
            print("登录异常", e)
            await self.record_login_log(
                sys_admin.id, sys_admin.username, err_msg if err_msg else "未知错误"
            )
            raise AppException(HttpResp.FAILED, echo_exc=True)

    async def logout(self, logout_in: SystemLogoutInSchema):
        """退出"""
        await RedisUtil.delete(f"{AdminConfig.backstage_token_key}{logout_in.token}")

    async def record_login_log(self, admin_id: int, username: str, error: str = ""):
        """记录登录日志"""
        ua = user_agents.parse(self.request.headers.get("user-agent", ""))
        try:
            row = insert(SystemLogLoginModel).values(
                admin_id=admin_id,
                username=username,
                ip=self.request.client.host if self.request.client else "",
                os=ua.os.family,
                browser=ua.browser.family,
                status=0 if error else 1,
            )
            await db.execute(row)
        except Exception as e:
            logging.error("记录登录日志异常 %s", str(e))
